/***************************************************************
 * Name:      SetupCreatorMain.cpp
 * Purpose:   Code for Application Frame
 * Author:    Jeremie Fouche (jeremie.fouche@gmail.com)
 * Created:   2007-05-05
 * Copyright: Jeremie Fouche ()
 * License:
 **************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include "setupframe.h"
#include "sc/interface.h"

# include <wx/aboutdlg.h>

#include "boost/foreach.hpp"

static const wxString sFrameTitle = _T("Setup");

static const wxColour bkOptionalColour = wxColour(0xfe, 0xdc, 0xba);

/// EVENT TABLE
BEGIN_EVENT_TABLE(SetupFrame, SetupFrameGui)
   EVT_MENU_RANGE(ID_MENU_ADD_BEGIN, ID_MENU_ADD_END, SetupFrame::OnContextMenuAddChild)
END_EVENT_TABLE()

/**
* SetupFrame constructor
*
* @param parent parent window (NULL)
*/
SetupFrame::SetupFrame(wxWindow* parent)
: SetupFrameGui(parent)
, m_pcClipboardElement(NULL)
{
    wxLog::SetActiveTarget( new wxLogTextCtrl(m_editLog) );
    SetIcon(wxICON(A));
    m_pgmAttributes->AddPage();
}

/**
* Called by the framework when the user need to open a context
*
* @param event
*/
void SetupFrame::OnFileOpen( wxCommandEvent& event )
{
	wxFileDialog dlg(this);
	dlg.SetWildcard( _("Setup creator context files (*.scc)|*.scc") );
	if (dlg.ShowModal() == wxID_OK)
	{
        int error = LoadContext(dlg.GetPath());
        if (error)
        {
            ::wxMessageBox(sc::error::str(error), _T("Setup Creator"), wxOK | wxICON_ERROR);
        }
	}
}

/**
* Called by the framework when the user need to save a setup
*
* @param event
*/
void SetupFrame::OnFileSave( wxCommandEvent& event )
{
    sc::setup::Element* pElement = GetElement( m_treeSetup->GetSelection() );
    if (pElement)
    {
        SaveAttributes(*pElement);
    }

    int error = SaveSetups();
    if (!error)
    {
        SetModify(false);
    }
    else
    {
        ::wxMessageBox(sc::error::str(error), _T("Setup Creator"), wxOK | wxICON_ERROR);
    }
}

/**
* Called by the framework when the user need to save a setup as ...
*  This menu is available only if there is one setup in the context
*
* @param event
*/
void SetupFrame::OnFileSaveAs( wxCommandEvent& event )
{
    assert(m_context.GetSetupCount() == 1);

	wxFileDialog dlg(this);
	dlg.SetWildcard( wxT("XML files (*.xml)|*.xml|All files (*.*)|*.*") );
	if (dlg.ShowModal() == wxID_OK)
	{
	    m_context.GetSetupContext(0)->SetXmlFile(dlg.GetPath());
	    OnFileSave(event);
	}
}

/**
* Called by the framework to set the state of the [SAVE AS...]
*
* @param event
*/
void SetupFrame::OnUpdateFileSaveAs( wxUpdateUIEvent& event )
{
    event.Enable(m_context.GetSetupCount() == 1);
}

/**
* Called by the framework when the user need to quit the application
*
* @param event
*/
void SetupFrame::OnFileExit( wxCommandEvent& event )
{
    Destroy();
}

/**
* Called by the framework when we want to add a child to the
*  current tree item.
*
* @param event
*/
void SetupFrame::OnEditAddChild( wxCommandEvent& event )
{
    wxTreeItemId tidParent = m_treeSetup->GetSelection();
    sc::SetupContext* pSetupCtx = GetSetupCtx(tidParent);
    sc::setup::Element* pParent = GetElement(tidParent);
    if (pSetupCtx && pParent)
    {
        std::set<wxString> listChildren;
        pParent->GetAvailableChildren(listChildren);
        wxArrayString vecChildren;
        BOOST_FOREACH (const wxString& sChild, listChildren)
        {
            vecChildren.Add(sChild);
        }
        if (vecChildren.Count() > 0)
        {
            DlgAddChild dlg(this, vecChildren);
            if (dlg.ShowModal() == wxID_OK)
            {
                int error = AddChild(*pSetupCtx, *pParent, dlg.GetChild(), tidParent);
                if (!error)
                {
                    SetModify();
                }
                else
                {
                    ::wxMessageBox(sc::error::str(error), wxT("Setup Creator"), wxOK | wxICON_ERROR);
                }
            }
        }
    }
}

/**
* Called by the framework to tell if the AddChild command is available
*
* @param event
*/
void SetupFrame::OnUpdateEditAddChild( wxUpdateUIEvent& event )
{
    bool bEnable = false;

	const sc::setup::Element* pElement = GetElement( m_treeSetup->GetSelection() );
	if (pElement)
	{
	    // Does pElement have children
	    bEnable = (pElement->GetConfig()->second.GetChildren().size() > 0);
	}
	event.Enable(bEnable);
}

/**
* Called by the framework when the user selected the [Delete child]
*
* @param event
*/
void SetupFrame::OnEditDeleteChild( wxCommandEvent& event )
{
    wxTreeItemId tidElement = m_treeSetup->GetSelection();
	sc::SetupContext* pSetupCtx  = GetSetupCtx(tidElement);
	sc::setup::Element* pElement = GetElement(tidElement);
	if (pSetupCtx && pElement)
	{
		int error = DeleteElement(*pSetupCtx, pElement, tidElement);
		if (!error)
		{
		    SetModify();
		}
		else
		{
            ::wxMessageBox(sc::error::str(error), wxT("Setup Creator"), wxOK | wxICON_ERROR);
		}
	}
}

/**
* Called by the framework to set the state of the [Delete child]
*
* @param event
*/
void SetupFrame::OnUpdateEditDeleteChild( wxUpdateUIEvent& event )
{
	bool bEnable = false;

    const sc::setup::Element* pcElement = GetElement( m_treeSetup->GetSelection() );
    if (pcElement)
    {
        // Can't remove UNIQUE Element
		bEnable = pcElement->GetConfig()->second.GetType() != sc::cfg::Element::UNIQUE;
	}
	event.Enable(bEnable);
}

/**
* Called by the framework when the user is copying the current element
*
* @param event
*/
void SetupFrame::OnEditCopy( wxCommandEvent& event )
{
    const sc::setup::Element* pcElement = GetElement( m_treeSetup->GetSelection() );
    if (pcElement)
    {
        m_pcClipboardElement = pcElement;
    }
}

/**
* Called by the framework to set the state of the [Copy]
*
* @param event
*/
void SetupFrame::OnUpdateEditCopy( wxUpdateUIEvent& event )
{
    event.Enable(GetElement( m_treeSetup->GetSelection() ) != NULL);
}

/**
* Called by the framework when the user want to paste the copied element
*
* @param event
*/
void SetupFrame::OnEditPaste( wxCommandEvent& event )
{
    assert( m_pcClipboardElement && m_pcClipboardElement->IsValid() );

    wxLogMessage(wxT("SetupFrame::OnEditPaste(%s)"), m_pcClipboardElement->GetName().c_str());

    wxTreeItemId hParent = m_treeSetup->GetSelection();
    sc::setup::Element* pElement = GetElement(hParent);
    sc::setup::TElements::iterator iterChild;
    if (pElement->AddChild(*m_pcClipboardElement, iterChild) == sc::error::NONE)
    {
        AddTreeChild(hParent, GetSetupCtx(hParent), &(*iterChild));

        SetModify();
    }
}

/**
* Called by the framework to set the state of the [Paste]
*
* @param event
*/
void SetupFrame::OnUpdateEditPaste( wxUpdateUIEvent& event )
{
    event.Enable(m_pcClipboardElement != NULL);
}

/**
* Called by the framework when the user right click on an item.
*   It show a context menu with available children that can be added, and
*   a delete menu item if possible
*
* @param event
*/
void SetupFrame::OnTreeSetupContextMenu( wxTreeEvent& event )
{
    wxTreeItemId tidElement = m_treeSetup->GetSelection();
    const sc::setup::Element* pcElement = GetElement(tidElement);
    if (pcElement)
    {
        wxMenu popup;

        // Add the available children
        std::set<wxString> listChildren;
        pcElement->GetAvailableChildren(listChildren);
        int id = ID_MENU_ADD_BEGIN;
        BOOST_FOREACH (const wxString& sChild, listChildren)
        {
            wxString sAdd;
            sAdd.Printf(_T("Add %s"), sChild.c_str());
            popup.Append(id, sAdd);
            id++;
        }

        // Can we delete the current item ?
	    if (pcElement->GetConfigType() != sc::cfg::Element::UNIQUE)
	    {
	        popup.AppendSeparator();
	        popup.Append(ID_EDIT_DELCHILD, _T("Delete"));
	    }

        // Popup the menu if there are available actions
	    if (popup.GetMenuItemCount() != 0)
	    {
	        PopupMenu(&popup);
	    }
    }
}

/**
* Called by the framework when clicking on a context menu to add an element
*
* @param event
*/
void SetupFrame::OnContextMenuAddChild( wxCommandEvent& event )
{
    wxTreeItemId tidParent = m_treeSetup->GetSelection();
    sc::SetupContext* pSetupCtx = GetSetupCtx(tidParent);
    sc::setup::Element* pParent = GetElement(tidParent);
    if (pSetupCtx && pParent)
    {
        int idx = event.GetId() - ID_MENU_ADD_BEGIN;

        // Get the available children
        std::set<wxString> listChildren;
        pParent->GetAvailableChildren(listChildren);
        BOOST_FOREACH (const wxString& sChild, listChildren)
        {
            if (idx == 0)
            {
                // We found the child we want to add
                int error = AddChild(*pSetupCtx, *pParent, sChild, tidParent);
                if (!error)
                {
                    SetModify();
                }
                else
                {
                    ::wxMessageBox(sc::error::str(error), wxT("Setup Creator"), wxOK | wxICON_ERROR);
                }
                break;
            }
            idx--;
        }
    }
}

/**
* Called by the framework when a tree selection is changing.
*  We save the attributes before changing the right panel
*
* @param event
*/
void SetupFrame::OnTreeSetupSelChanging( wxTreeEvent& event )
{
    wxTreeItemId tidElement = event.GetOldItem();
	sc::SetupContext* pSetupCtx = GetSetupCtx(tidElement);
	sc::setup::Element* pElement = GetElement(tidElement);
	if (pSetupCtx && pElement)
	{
	    // First, we verify that all attributes are OK
        SaveAttributes(*pElement);

        // Update current element and its parents
        UpdateElement(tidElement);
	}
}

/**
* Called by the framework when a tree selection has changed.
*  Set all the controls of the right panel
*
* @param event
*/
void SetupFrame::OnTreeSetupSelChanged( wxTreeEvent& event )
{
    RemoveAllControls();

    // Show the attributes of the new selected Element
    wxTreeItemId tidElement = m_treeSetup->GetSelection();
	sc::SetupContext* pSetupCtx  = GetSetupCtx(tidElement);
	sc::setup::Element* pElement = GetElement(tidElement);
	if (pElement)
	{
        SetControls(*pSetupCtx, *pElement);
	}

	m_pgmAttributes->Refresh();
}

/**
* Called by the framework while right clicking on a tree item.
*   This must select the item.
*
* @param event
*/
void SetupFrame::OnTreeSetupRightClick( wxTreeEvent& event )
{
    if (m_treeSetup->GetSelection() != event.GetItem())
    {
        m_treeSetup->SelectItem(event.GetItem());
    }
}

/**
* Called by the framework when an attribute has changed.
*
* @param event
*/
void SetupFrame::OnPGAttributeChanged( wxPropertyGridEvent& event )
{
    SetModify(true);
}

/**
* Called by the framework when the user ask to exit app
* If the setup is modified, ask the user to save
*
* @return true if everything is destroyed
*/
bool SetupFrame::Destroy()
{
	if (!m_bModified)
		return wxFrame::Destroy();
	
    bool bDestroyed = false;
	int answer = wxMessageBox(_("Do you want to save file(s) before exit application ?"), _("Confirm"), wxYES_NO | wxCANCEL, this);
    switch (answer)
    {
	case wxYES :
		SaveSetups();
	case wxNO :
		bDestroyed = wxFrame::Destroy();
		break;
	default:
        break;
    }
    return bDestroyed;
}

/**
* Update a tree item view
*
* @param tid tree item ID
*/
void SetupFrame::UpdateElement(const wxTreeItemId& tid)
{
    if (!tid.IsOk())
        return;

	const sc::SetupContext* pcSetupCtx  = GetSetupCtx(tid);
	const sc::setup::Element* pcElement = GetElement(tid);
	if (pcSetupCtx && pcElement)
	{
        // Change the tree label if necessary
        m_treeSetup->SetItemText(tid, pcSetupCtx->GetElementLabel(*pcElement).c_str());

        // Sort the items
        m_treeSetup->SortChildren(m_treeSetup->GetItemParent(tid));

        wxColour itemColor = *wxBLACK;
	    if (pcElement->IsValid())
	    {
	        // Update Parent
	        UpdateElement(m_treeSetup->GetItemParent(tid));
	    }
	    else
	    {
	        itemColor = *wxRED;
	    }
	    m_treeSetup->SetItemTextColour(tid, itemColor);
	}
}

/**
* Load a context
*
* @param sFilename
*
* @return the context loading error
*/
int SetupFrame::LoadContext(const wxString& sFilename)
{
    wxLogMessage(wxT("SetupFrame::LoadContext(%s)"), sFilename.c_str());
    int error = m_context.Load(sFilename);
    if (!error)
    {
        Load();
    }
    else
    {
        ::wxMessageBox(sc::error::str(error), wxT("Setup Creator"), wxOK | wxICON_ERROR);
    }
    return error;
}

/**
* Load all the information in the frame :
*  - Load the icons
*  - Fill the tree
*/
void SetupFrame::Load(void)
{
    m_treeSetup->DeleteAllItems();

    SetModify(false);

    // Load the icons
    static wxImageList imgList(16,16);
    imgList.RemoveAll();
    m_mapIcons.clear();

    for (size_t idx = 0; idx < m_context.GetSetupCount(); ++idx)
    {
        const sc::SetupContext* pcSetupCtx = m_context.GetSetupContext(idx);
        BOOST_FOREACH (const sc::SetupContext::TMmiElements::value_type& rcMmiVal, pcSetupCtx->GetMmiElements())
        {
            const wxString& sIcon = rcMmiVal.second.sIcon;
            if (!sIcon.empty())
            {
                wxIcon icon(sIcon, wxBITMAP_TYPE_ICO);
                if (icon.IsOk())
                {
                    int idx = imgList.Add(icon);
                    if (idx != -1)
                    {
                        m_mapIcons[rcMmiVal.first] = idx;
                    }
                }
            }
        }
    }
    m_treeSetup->SetImageList(&imgList);

    wxTreeItemId idRoot = m_treeSetup->AddRoot(wxT("SETUP"));
    assert(idRoot.IsOk());
    bool bValid = true;
    for (size_t idx = 0; idx < m_context.GetSetupCount(); ++idx)
    {
        const sc::SetupContext* pcSetupCtx = m_context.GetSetupContext(idx);
        assert(pcSetupCtx);
        const sc::setup::Element* pcRoot = pcSetupCtx->GetSetup().Get();
        // Fill the tree recursively
        AddTreeChild(idRoot, pcSetupCtx, pcRoot);

        bValid &= pcRoot->IsValid();
    }

    if (!bValid)
    {
        ::wxMessageBox(_("The setup is not actualy correct !"), _("Warning"), wxOK|wxICON_EXCLAMATION, this);
    }
}

/**
* Called by the framework we the user wants to preview the xml source
*
* @param event
*/
void SetupFrame::OnViewPreview( wxCommandEvent& event )
{
    DlgPreview dlg(this, m_context);
    dlg.ShowModal();
}

/**
* Called by the framework we the user to update the [preview]
*
* @param event
*/
void SetupFrame::OnUpdateViewPreview( wxUpdateUIEvent& event )
{
    event.Skip();
}

/**
* Called by the framework we the user wants to see the about dialog
*
* @param event
*/
void SetupFrame::OnHelpAbout( wxCommandEvent& event )
{
    wxAboutDialogInfo infos;
    infos.SetName(wxT("SetupCreator - Setup"));
    infos.SetVersion(SC_VERSION);
    infos.AddDeveloper(wxT("Jérémie Fouché"));
    infos.SetWebSite(wxT("http://code.google.com/p/setupcreator/"));
    wxAboutBox(infos);
}

/**
* Add a child and it's children to the tree.
*
* @param hParent    handle to the tree item parent
* @param pcSetupCtx context used to show element
* @param pcElement  element to be added to the tree
*
* @return handle to the tree item created
*/
wxTreeItemId SetupFrame::AddTreeChild(const wxTreeItemId& hParent, const sc::SetupContext* pcSetupCtx, const sc::setup::Element* pcElement)
{
    assert(hParent.IsOk() && pcSetupCtx && pcElement);

    // Get the label
    wxString sLabel = pcSetupCtx->GetElementLabel(*pcElement);

    // Get the icon ID
    TIcons::const_iterator iterIcon = m_mapIcons.find(pcElement->GetName());
    int idIcon = (iterIcon == m_mapIcons.end()) ? -1 : iterIcon->second;

    // Add the child to the tree
    wxTreeItemId newItem = m_treeSetup->AppendItem(hParent, sLabel, idIcon);
    assert(newItem.IsOk());

    // Assign the Element to the new tree item
	ElementTID* ptid = new ElementTID( const_cast<sc::SetupContext*>(pcSetupCtx)
	                                 , const_cast<sc::setup::Element*>(pcElement)
	                                 );
	m_treeSetup->SetItemData(newItem, ptid);

	// Put the Element in RED if invalid
	if (!pcElement->IsValid())
	{
        wxLogMessage(wxT("SetupFrame::AddTreeChild(%s) - INVALID"), pcElement->GetName().c_str());
	    m_treeSetup->SetItemTextColour(newItem, *wxRED);
	}

	// Add the existing children
	BOOST_FOREACH (const sc::setup::Element& rcChild, pcElement->GetChildren())
	{
		AddTreeChild(newItem, pcSetupCtx, &rcChild);
	}

	// Sort the items
    m_treeSetup->SortChildren(newItem);

	return newItem;
}

/**
* Get the SetupContext corresponding to a tree item
*
* @return the SetupContext, or NULL
*/
sc::SetupContext* SetupFrame::GetSetupCtx(const wxTreeItemId& tid) const
{
    sc::SetupContext* pSetupCtx = NULL;
    if (tid.IsOk())
    {
        ElementTID* pElemTID = dynamic_cast<ElementTID*>(m_treeSetup->GetItemData(tid));
        if (pElemTID)
        {
            pSetupCtx = pElemTID->m_pSetupCtx;
        }
    }
    return pSetupCtx;
}

/**
* Get the Setup Element corresponding to a tree item
*
* @return the Element, or NULL
*/
sc::setup::Element* SetupFrame::GetElement(const wxTreeItemId& tid) const
{
    sc::setup::Element* pElement = NULL;
    if (tid.IsOk())
    {
        ElementTID* pElemTID = dynamic_cast<ElementTID*>(m_treeSetup->GetItemData(tid));
        if (pElemTID)
        {
            pElement = pElemTID->m_pElement;
        }
    }
    return pElement;
}

/**
* Remove all the right panel controls, representing the Element attributes
*/
void SetupFrame::RemoveAllControls(void)
{
    m_pgmAttributes->ClearPage(0);
}

/**
* Set all the controls in the right panel, according to the attributes
*  of the Element.
*
* @param rSetupCtx Setup context
* @param rElement  Element of which we are creating the attributes
*/
void SetupFrame::SetControls(sc::SetupContext& rSetupCtx, sc::setup::Element& rElement)
{
    m_pgmAttributes->Append(new wxPropertyCategory(_T("Attributes")));

	// Create all the controls for the attributes of the current Element
	sc::setup::TAttributes::iterator iter;
	for (iter = rElement.AttributesBegin(); iter != rElement.AttributesEnd(); iter++)
	{
		// Get the attribute
		sc::setup::Attribute& rAttrib = *iter;

		wxString sLabel = rSetupCtx.GetAttributeLabel(rAttrib);
		wxPGId pgId = 0;
		if (rAttrib.m_pcConf->GetType() == sc::cfg::Attribute::CHOICE)
		{
			wxArrayString choices;
			BOOST_FOREACH (const wxString& sChoice, rAttrib.m_pcConf->GetChoices())
			{
				choices.Add(sChoice);
			}
            pgId = m_pgmAttributes->Append( new wxEnumProperty( sLabel
                                                              , rAttrib.GetName()
                                                              , choices
                                                              , wxPG_EMPTY_ARRAYINT
                                                              , choices.Index(rAttrib.m_sValue.c_str())
                                                              )
                                           );
		}
		else
		{
		    switch (rSetupCtx.GetAttributeType(rAttrib))
		    {
            case sc::SetupContext::AttribType::DIRECTORY :
                pgId = m_pgmAttributes->Append( new wxDirProperty( sLabel
                                                                 , rAttrib.GetName()
                                                                 , rAttrib.m_sValue
                                                                 )
                                               );
                break;
            case sc::SetupContext::AttribType::FILE :
                pgId = m_pgmAttributes->Append( new wxFileProperty( sLabel
                                                                  , rAttrib.GetName()
                                                                  , rAttrib.m_sValue
                                                                  )
                                               );
                break;
            case sc::SetupContext::AttribType::STRING :
            default:
                pgId = m_pgmAttributes->Append( new wxStringProperty( sLabel
                                                                    , rAttrib.GetName()
                                                                    , rAttrib.m_sValue
                                                                    )
                                              );
                break;
		    }
            m_pgmAttributes->SetPropertyValidator(pgId,  AttributeValidator(*rAttrib.m_pcConf, rSetupCtx.GetAttributeError(rAttrib)));
		}
		assert(pgId);
        m_pgmAttributes->SetPropertyHelpString(pgId, rSetupCtx.GetAttributeHelp(rAttrib));
        if (rAttrib.m_pcConf->IsOptional())
        {
            wxPGPropArg pgPropArg(pgId);
            m_pgmAttributes->SetPropertyBackgroundColour(pgPropArg, bkOptionalColour);
        }
	}
}

/**
* Save all the attributes of the current element
*/
bool SetupFrame::SaveAttributes(sc::setup::Element& rElement)
{
    wxLogMessage(wxT("SetupFrame::SaveAttributes(%s)"), rElement.GetName().c_str());

    bool bOk = true;

    sc::setup::TAttributes::iterator iterAttrib;
	for (iterAttrib = rElement.AttributesBegin(); bOk && iterAttrib != rElement.AttributesEnd(); ++iterAttrib)
	{
	    const sc::cfg::Attribute& rcCfgAttrib = *(iterAttrib->m_pcConf);

        wxPGId pgId = m_pgmAttributes->GetPropertyByName(rcCfgAttrib.GetName());
	    wxString sValue = m_pgmAttributes->GetPropertyValueAsString(rcCfgAttrib.GetName().c_str());
	    if (!rcCfgAttrib.IsOptional() || !sValue.empty())
        {
            bOk = iterAttrib->m_pcConf->Validate(sValue.c_str());
            if (!bOk)
            {
                // Attribute invalide
                m_pgmAttributes->SelectProperty(pgId, true);
            }
        }
		iterAttrib->m_sValue = sValue;
	}
	return bOk;
}

/**
* Add a child to an element of the setup
*
* @param rSetupCtx  Context used for this element
* @param rParent    Element parent
* @param sChild     name of the child to be added
* @param hParent    handle of the parent tree item
*
* @return add error
*/
int SetupFrame::AddChild(sc::SetupContext& rSetupCtx, sc::setup::Element& rParent, const wxString& sChild, const wxTreeItemId& hParent)
{
	sc::setup::Element child(sChild, wxEmptyString, rSetupCtx.GetSetup().GetConfig().GetElements().find(sChild));
	sc::setup::TElements::iterator iterChild;
	int error = rParent.AddChild(child, iterChild);
	if (!error)
	{
        wxTreeItemId hChild = AddTreeChild(hParent, &rSetupCtx, &(*iterChild));
        m_treeSetup->SortChildren(hParent);
        m_treeSetup->SelectItem(hChild);
	}
	return error;
}

/**
* Delete an element of the setup
*
* @param rSetupCtx  SetupContext of the current Element
* @param pElement  Element to delete
* @param hElement  handle of the element tree item to be removed
*
* @return delete error
*/
int SetupFrame::DeleteElement(sc::SetupContext& rSetupCtx, sc::setup::Element* pElement, const wxTreeItemId& hElement)
{
	int error =rSetupCtx.GetSetup().DeleteElement(pElement);
	if (!error)
	{
        // First, we must save the parent item to select it after delete
        wxTreeItemId tidParent = m_treeSetup->GetItemParent(hElement);
        m_treeSetup->Delete(hElement);
        m_treeSetup->SelectItem(tidParent);
	}
	return error;
}

/**
* Save the setups (ie : XML files)
*
* @return saving error
*/
int SetupFrame::SaveSetups()
{
    sc::setup::Element* pElement = GetElement( m_treeSetup->GetSelection() );
    if (pElement)
    {
        SaveAttributes(*pElement);
    }
    return m_context.SaveSetups();
}

/**
* Return Update the title of the frame, regarding the context file and the modified state
*/
void SetupFrame::UpdateTitle(void)
{
    wxString sTitle(m_context.GetTitle());
    if (m_bModified)
    {
        sTitle << _T(" *");
    }
    SetTitle(sTitle);
}

/**
* Modify the state of the context
*
* @param bModify
*/
void SetupFrame::SetModify(bool bModify)
{
    m_bModified = bModify;

    UpdateTitle();
}
